package cn.actoncode.boot.framework.common.util.speech;

import cn.actoncode.boot.framework.common.enums.SpeechChannelEnum;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SSMLUtil {

    static final List<String> SYMBOL_LIST = Arrays.asList(",", "，", "。", "!", "！", "?", "？", "\"", "、", "\n");

    public static String buildDefaultSsml(String content, String voice, String style, String role, String region, Integer channel) {
        if (channel == SpeechChannelEnum.MICROSOFT.getCode()) {
            return buildDefaultMSSsml(content, voice, style, role, region);
        } else if (channel == SpeechChannelEnum.ALIYUN.getCode()) {
            return buildDefaultAliSsml(content, voice, style);
        } else {
            return buildDefaultVlocSsml(content, style);
        }
    }

    public static String buildDefaultMSSsml(String content, String voice, String style, String role, String region) {
        return buildMSSsml(content, voice, style, role, "1", "100", "0", region);
    }

    public static String buildDefaultAliSsml(String content, String voice, String style) {
        return buildAliSsml(content, voice, style, "0", "100", "0");
    }

    public static String buildDefaultVlocSsml(String content, String style) {
        return buildVolcSsml(content, style, "0", "100", "0");
    }

    public static String buildMSSsml(String content, String voice, String style, String role, String rate, String volume, String pitch, String region) {
        // 处理多音字
        content = processPolyphonicWordMs(content);
        // 处理停顿
        content = processPause(content);
        if (StrUtil.isEmpty(region)) {
            region = "zh-CN";
        }
        StringBuilder text = new StringBuilder();
        if (StrUtil.isNotEmpty(role) && StrUtil.isNotEmpty(style)) {
            text.append("<mstts:express-as")
                    .append(" role=\"").append(role).append("\"")
                    .append(" style=\"").append(style).append("\"")
                    .append(">")
                    .append("<prosody")
                    .append(" rate=\"").append(rate).append("\"")
                    .append(" volume=\"").append(volume).append("\"")
                    .append(" pitch=\"").append(pitch).append("%").append("\"")
                    .append(" >")
                    .append(content)
                    .append("</prosody>")
                    .append("</mstts:express-as>");
        } else if (StrUtil.isNotEmpty(role)) {
            text.append("<mstts:express-as")
                    .append(" role=\"").append(role).append("\"")
                    .append(">")
                    .append("<prosody")
                    .append(" rate=\"").append(rate).append("\"")
                    .append(" volume=\"").append(volume).append("\"")
                    .append(" pitch=\"").append(pitch).append("%").append("\"")
                    .append(" >")
                    .append(content)
                    .append("</prosody>")
                    .append("</mstts:express-as>");

        } else if (StrUtil.isNotEmpty(style)) {
            text.append("<mstts:express-as")
                    .append(" style=\"").append(style).append("\"")
                    .append(">")
                    .append("<prosody")
                    .append(" rate=\"").append(rate).append("\"")
                    .append(" volume=\"").append(volume).append("\"")
                    .append(" pitch=\"").append(pitch).append("%").append("\"")
                    .append(" >")
                    .append(content)
                    .append("</prosody>")
                    .append("</mstts:express-as>");

        } else {
            text.append("<prosody")
                    .append(" rate=\"").append(rate).append("\"")
                    .append(" volume=\"").append(volume).append("\"")
                    .append(" pitch=\"").append(pitch).append("%").append("\"")
                    .append(" >")
                    .append(content)
                    .append("</prosody>");
        }

        StringBuilder result = new StringBuilder();
        result.append("<speak version=\"1.0\" xmlns=\"http://www.w3.org/2001/10/synthesis\" ")
                .append("xmlns:mstts=\"https://www.w3.org/2001/mstts\" xmlns:emo=\"http://www.w3.org/2009/10/emotionml\" ")
                .append("xml:lang=\"").append(region).append("\"").append(">")
                .append("<voice ")
                .append("name=\"").append(voice).append("\"").append(">")
                .append(text)
                .append("</voice> ")
                .append("</speak>");

        return result.toString();
    }

    public static String buildAliSsml(String content, String voice, String style, String rate, String volume, String pitch) {
        // 处理多音字
        content = processPolyphonicWordAli(content);
        // 处理停顿
        content = processPause(content);
        StringBuilder text = new StringBuilder();
        if (StrUtil.isEmpty(style)) {
            text.append(content);
        } else {
            text.append("<emotion")
                    .append(" category=\"").append(style).append("\"")
                    .append(" intensity=\"1.0\"").append(">")
                    .append(content)
                    .append("</emotion>");
        }
        StringBuilder result = new StringBuilder();
        result.append("<speak")
                .append(" voice=\"").append(voice).append("\"")
                .append(" rate=\"").append(rate).append("\"")
                .append(" volume=\"").append(volume).append("\"")
                .append(" pitch=\"").append(pitch).append("%").append("\"")
                .append(">")
                .append(text)
                .append("</speak>");
        return result.toString();
    }

    public static String buildVolcSsml(String content, String style, String rate, String volume, String pitch) {
        // 处理多音字
        content = processPolyphonicWordVolc(content);
        // 处理停顿
        content = processPause(content);
        StringBuilder text = new StringBuilder();
        if (StrUtil.isEmpty(style)) {
            text.append(content);
        } else {
            text.append("<emotion")
                    .append(" style=\"").append(style).append("\"")
                    .append(" style_ratio=\"1.0\"").append(">")
                    .append(content)
                    .append("</emotion>");
        }
        StringBuilder result = new StringBuilder();
        int volumeInt = Integer.parseInt(volume);
        int pitchInt = Integer.parseInt(pitch);
        double pitchDouble = pitchInt < 0 ? 0.005 * pitchInt + 1 : 0.01 * pitchInt + 1;
        result.append("<speak>").append("<prosody")
                .append(" speed=\"").append(rate).append("\"")
                .append(" volume=\"").append(volumeInt * 0.015 + 0.5).append("\"")
                .append(" pitch=\"").append(pitchDouble).append("\"")
                .append(">")
                .append(text)
                .append("</prosody>")
                .append("</speak>");
        return result.toString();
    }

    public static String processSymbol(String str) {
        String regEx="[\\s~·`!！@#￥$%^&*（()）\\-——\\-_=+【\\[\\]】｛{}｝\\|、\\\\；;‘'“”\"，,《<》>、「」/]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.replaceAll("");
    }

    public static String processPolyphonicWordMs(String str) {
        int left = str.indexOf("[=");
        if (left > 0) {
            int right = str.indexOf("]", left);
            String word = str.substring(left -1, left);
            String ph = str.substring(left + 2, right);
            StringBuilder phsb = new StringBuilder();
            if (StringUtils.isNumeric(ph.substring(ph.length() -1))) {
                phsb.append(ph);
                phsb.insert(ph.length() - 1, " ");
            } else {
                phsb.append(ph).append(" 5");
            }
            ph = phsb.toString().replace("ü", "v");
            String str1 = str.substring(left - 1, right + 1);
            StringBuilder sb = new StringBuilder();
            sb.append("<phoneme alphabet=\"sapi\" ph=\"")
                    .append(ph).append("\"").append(">")
                    .append(word)
                    .append("</phoneme>");
            str = str.replace(str1, sb);
        }
        if (str.indexOf("[=") > 0) {
            str = processPolyphonicWordMs(str);
        }
        return str;
    }

    public static String processPolyphonicWordAli(String str) {
        int left = str.indexOf("[=");
        if (left > 0) {
            int right = str.indexOf("]", left);
            String word = str.substring(left -1, left);
            String ph = str.substring(left + 2, right);
            if (!StringUtils.isNumeric(ph.substring(ph.length() -1))) {
                ph = ph + "5";
            }
            ph = ph.replace("ü", "v");
            String str1 = str.substring(left - 1, right + 1);
            StringBuilder sb = new StringBuilder();
            sb.append("<phoneme alphabet=\"py\" ph=\"")
                    .append(ph).append("\"").append(">")
                    .append(word)
                    .append("</phoneme>");
            str = str.replace(str1, sb);
        }
        if (str.indexOf("[=") > 0) {
            str = processPolyphonicWordAli(str);
        }
        return str;
    }

    public static String processPolyphonicWordVolc(String str) {
        int left = str.indexOf("[=");
        if (left > 0) {
            int right = str.indexOf("]", left);
            String word = str.substring(left -1, left);
            String ph = str.substring(left + 2, right);
            if (!StringUtils.isNumeric(ph.substring(ph.length() -1))) {
                ph = ph + "5";
            }
            ph = ph.replace("ü", "v");
            String str1 = str.substring(left - 1, right + 1);
            StringBuilder sb = new StringBuilder();
            sb.append("<phoneme alphabet=\"py\" ph=\"")
                    .append(ph).append("\"").append(">")
                    .append(word)
                    .append("</phoneme>");
            str = str.replace(str1, sb);
        }
        if (str.indexOf("[=") > 0) {
            str = processPolyphonicWordVolc(str);
        }
        return str;
    }

    public static String processPause(String str) {
        int left = str.indexOf("[+");
        if (left > -1) {
            int right = str.indexOf("]", left);
            String time = str.substring(left + 1, right);
            String str1 = str.substring(left, right + 1);
            StringBuilder sb = new StringBuilder();
            sb.append("<break time=\"")
                    .append(time.replace("秒", "s"))
                    .append("\"")
                    .append("/>");
            str = str.replace(str1, sb);
        }
        if (str.contains("[+")) {
            str = processPause(str);
        }
        return str;
    }

    public static int getIndex(String str, int index) {
        int symbolIndex = 0;
        for (String symbol : SYMBOL_LIST) {
            int i = str.lastIndexOf(symbol, index);
            symbolIndex = Math.max(i, symbolIndex);
        }
        return symbolIndex;
    }

}
